import numpy as np
import random

class SnakeGame:
    def __init__(self, width=640, height=480, block_size=20):
        self.width = width
        self.height = height
        self.block_size = block_size
        self.reset()

    def reset(self):
        """重置游戏状态"""
        self.snake = [
            (self.width // 2, self.height // 2),
            (self.width // 2 - self.block_size, self.height // 2),
            (self.width // 2 - 2 * self.block_size, self.height // 2)
        ]
        self.direction = (self.block_size, 0)  # 初始向右移动
        self.food = self._generate_food()
        self.score = 0
        self.game_over = False

    def _generate_food(self):
        """生成不与蛇身重叠的食物坐标"""
        while True:
            x = random.randint(1, (self.width - self.block_size) // self.block_size) * self.block_size
            y = random.randint(1, (self.height - self.block_size) // self.block_size) * self.block_size
            food_pos = (x, y)
            if food_pos not in self.snake:
                return food_pos

    def change_direction(self, new_direction):
        """改变移动方向（防止180度反向）"""
        if (new_direction[0] * -1, new_direction[1] * -1) != self.direction:
            self.direction = new_direction

    def update(self):
        """更新游戏状态"""
        if self.game_over:
            return

        # 计算新头部位置
        head_x, head_y = self.snake[0]
        new_head = (head_x + self.direction[0], head_y + self.direction[1])

        # 边界碰撞检测
        if (new_head[0] < 0 or new_head[0] >= self.width or
            new_head[1] < 0 or new_head[1] >= self.height):
            self.game_over = True
            return

        # 自身碰撞检测
        if new_head in self.snake:
            self.game_over = True
            return

        # 添加新头部
        self.snake.insert(0, new_head)

        # 食物碰撞检测
        if new_head == self.food:
            self.score += 10
            self.food = self._generate_food()
        else:
            # 未吃到食物则移除尾部
            self.snake.pop()

    def get_state(self):
        """获取当前游戏状态"""
        return {
            "snake": self.snake,
            "food": self.food,
            "score": self.score,
            "game_over": self.game_over
        }

# 单元测试
if __name__ == "__main__":
    game = SnakeGame()
    
    # 测试1：初始状态验证
    assert len(game.snake) == 3, "初始蛇身长度应为3"
    assert game.score == 0, "初始分数应为0"
    assert not game.game_over, "初始游戏状态不应为结束"
    
    # 测试2：移动测试
    game.change_direction((20, 0))  # 向右移动
    game.update()
    assert game.snake[0] == (game.snake[1][0] + 20, game.snake[1][1]), "蛇头未正确移动"
    
    # 测试3：食物碰撞测试
    initial_length = len(game.snake)
    game.food = (game.snake[0][0] + 20, game.snake[0][1])  # 将食物放在蛇头前方
    game.update()  # 移动后吃到食物
    assert len(game.snake) == initial_length + 1, "吃到食物后蛇身未增长"
    assert game.score == 10, "吃到食物后分数未增加"
    
    # 测试4：边界碰撞测试
    game = SnakeGame()  # 重置游戏
    game.snake[0] = (game.width, game.height // 2)  # 移动到右边界
    game.update()
    assert game.game_over, "边界碰撞未触发游戏结束"
    
    print("所有单元测试通过！")